

namespace Stee.CAP8.APIGateway.JWTAuthentication.Controllers
{
    using System;
    using System.Linq;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using NLog;
    using RestSharp;

    [Route("api")]
    [ApiController]
    public class ApiController : ControllerBase
    {
        /// <summary>
        /// Logger utility
        /// </summary>
        private readonly static Logger logger = LogManager.GetCurrentClassLogger();


        /// <summary>
        /// Authentication domain
        /// </summary>
        private const string authDomain = "https://dev-ztpxw325.au.auth0.com/oauth/token";

        /// <summary>
        /// Hosted web API application URL (Windows IIS / Docker/ etc.)
        /// </summary>
        private const string apiURL = "http://localhost:8000";

        private const string client_id = "tZvRGPm69zGjP4DgODxkos0mU2mSGoRy";
        private const string client_secret = "CkOsfTRhmSekl4QHjlPrHaSx8lFp5ufIEdkIlmwBUBjuEUzZb6oHFzHmySEoOFsb";
        private const string audience = "Envoy authentication RS";
        private const string grant_type = "client_credentials";


        #region Public Methods

        [HttpGet("public")]
        public IActionResult Public()
        {
            try
            {
                return Ok(new
                {
                    Message = "Hello from a public endpoint! You don't need to be authenticated to see this."
                });
            }
            catch (Exception ex)
            {
                logger.Error(ex, ex.Message);
                throw;
            }
        }

        /// <summary>
        /// Gets a new access token.
        /// TODO: Method must be modified to take in some user information or load a log in page to generate new access token.
        /// </summary>
        /// <returns>Return new access token</returns>
        [HttpGet("gettoken")]
        public IActionResult GetToken()
        {
            try
            {
                string token = this.RequestToken();

                ////// Parse response for access token
                //dynamic dynamicToken = JObject.Parse(token);
                //JWTAccessToken accessToken = new JWTAccessToken(dynamicToken);

                return Ok(token);
            }
            catch (Exception ex)
            {
                logger.Error(ex, ex.Message);
                throw;
            }
        }

        [HttpGet("private")]
        [Authorize]
        public IActionResult Private()
        {
            try
            {
                return Ok(new
                {
                    Message = "Hello from a private endpoint! You need to be authenticated to see this."
                });
            }
            catch (Exception ex)
            {
                logger.Error(ex, ex.Message);
                throw;
            }
        }

        [HttpGet("private-scoped")]
        [Authorize("read:messages")]
        public IActionResult Scoped()
        {
            try
            {
                return Ok(new
                {
                    Message = "Hello from a private endpoint! You need to be authenticated and have a scope of read:messages to see this."
                });
            }
            catch (Exception ex)
            {
                logger.Error(ex, ex.Message);
                throw;
            }
        }

        // This is a helper action. It allows you to easily view all the claims of the token.
        [HttpGet("claims")]
        public IActionResult Claims()
        {
            try
            {
                return Ok(User.Claims.Select(c =>
                        new
                        {
                            c.Type,
                            c.Value
                        }));
            }
            catch (Exception ex)
            {
                logger.Error(ex, ex.Message);
                throw;
            }
        }

        #endregion Public Methods


        #region Private Methods

        /// <summary>
        /// Request for new JWT token
        /// </summary>
        /// <returns>Return JWT token</returns>
        private string RequestToken()
        {
            try
            {
                RestClient client = new RestClient(authDomain);
                RestRequest request = new RestRequest(Method.POST);

                ////// Add request parameter method 1, OK
                //request.AddHeader("content-type", "application/json");
                //request.AddParameter("application/json", "{\"client_id\":\"tZvRGPm69zGjP4DgODxkos0mU2mSGoRy\",\"client_secret\":\"CkOsfTRhmSekl4QHjlPrHaSx8lFp5ufIEdkIlmwBUBjuEUzZb6oHFzHmySEoOFsb\",\"audience\":\"Envoy authentication RS\",\"grant_type\":\"client_credentials\"}", ParameterType.RequestBody);

                //// Add request parameter method 2, OK
                request.AddParameter(nameof(client_id), client_id);
                request.AddParameter(nameof(client_secret), client_secret);
                request.AddParameter(nameof(audience), audience);
                request.AddParameter(nameof(grant_type), grant_type);

                //// Request
                IRestResponse response = client.Execute(request);
                PrintResponse(response);

                return response.Content;
            }
            catch (Exception ex)
            {
                logger.Error(ex, ex.Message);
                return null;
            }
        }

        #endregion Private Methods


        #region Static Methods

        /// <summary>
        /// Print the returned response
        /// </summary>
        /// <param name="response">REST response</param>
        private static void PrintResponse(IRestResponse response)
        {
            if (response == null || (int)response.StatusCode >= 300)
            {
                //// Error
                logger.Error($"[Status code - {response.StatusCode}] ERROR => {response.ErrorMessage}");
            }
            else
            {
                //// Success
                logger.Info($"[Status code - {response.StatusCode}] {response.Content}");
            }
        }

        #endregion Static Methods
    }
}
